﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk.Query;

namespace MSCRMSolutionImport
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Clear();
            if (args.Length < 2 || args.Length > 3)
            {
                throw new ArgumentException("Arguments missing! Expected 'MSCRMSolutionImport.exe [crm connection string] [solution file] [publish{true/false}]'");
            }
            var connectionString = args[0];
            var solutionFile = args[1];
            bool publish = false;
            if (args.Length > 2)
            {
                publish = bool.Parse(args[2]);
            }
            var jobid = Guid.NewGuid();

            var connection = CrmConnection.Parse(connectionString);
            connection.Timeout = new TimeSpan(1, 0, 0);
            var service = new OrganizationService(connection);

            try
            {
                log(string.Format("Importing solution file {0}", solutionFile));

                Console.WriteLine(string.Format("Importing solution with jobid '{0}'...", jobid.ToString()));

                var req = new ImportSolutionRequest();
                req.CustomizationFile = File.ReadAllBytes(solutionFile);
                req.ImportJobId = jobid;

                Thread t = new Thread(new ParameterizedThreadStart(ProgressReport));
                t.Start(new ProgressReportArgs() { JobId = jobid, ConnectionString = connectionString });

                var resp = (ImportSolutionResponse)service.Execute(req);

                while (t.IsAlive) { }

                Console.WriteLine("Import Done");
                log(string.Format("Finished importing solution file {0}", solutionFile));

                if (publish)
                {
                    var pubreq = new PublishAllXmlRequest();
                    Console.WriteLine("Publishing customizations...");
                    log("Publishing.");
                    var pubresp = (PublishAllXmlResponse)service.Execute(pubreq);
                    Console.WriteLine("Publish Done");
                }

                log("Import complete.");

            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex.Message);
                Console.ResetColor();
                log(ex.Message);
                //todo: save import log for debugging import errors
            }
            finally
            {
                var reportfile = solutionFile.Replace(".zip", "_importlog.xml");
                try
                {
                    if (File.Exists(reportfile))
                    {
                        File.Delete(reportfile);
                    }
                }
                catch { }

                try
                {
                    RetrieveFormattedImportJobResultsRequest resultReq = new RetrieveFormattedImportJobResultsRequest()
                    {
                        ImportJobId = jobid
                    };
                    var resultResp = (RetrieveFormattedImportJobResultsResponse)service.Execute(resultReq);
                    File.WriteAllText(reportfile, resultResp.FormattedResults);
                }
                catch (Exception ex)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(ex.Message);
                    Console.ResetColor();
                    log(ex.Message);
                    //todo: save import log for debugging import errors
                }
            }
        }

        private static void log(string message)
        {
            try
            {
                File.AppendAllText("MSCRMSolutionImport.log", string.Format("{0} - {1}{2}", DateTime.Now.ToString("yyyyMMdd hh:mm:ss"), message, Environment.NewLine));
            }
            catch { }
        }

        private static void ProgressReport(object args)
        {
            var connection = CrmConnection.Parse(((ProgressReportArgs)args).ConnectionString);
            var service = new OrganizationService(connection);
            try
            {
                var job = service.Retrieve("importjob", ((ProgressReportArgs)args).JobId, new ColumnSet("solutionname", "progress"));
                decimal progress = Convert.ToDecimal(job["progress"]);

                Console.WriteLine("{0:N0}%", progress);

                if (progress == 100) { return; }
            }
            catch { }
            Thread.Sleep(5000);
            ProgressReport(args);
        }

        private class ProgressReportArgs
        {
            public Guid JobId { get; set; }
            public string ConnectionString { get; set; }
        }
    }
}
